www.gusucode.com > VC++ 双缓存无闪烁绘制动态曲线 > VC++ 双缓存无闪烁绘制动态曲线/gusucode/CurveDrawing/clPlot.cpp
//Download by http://www.NewXing.com // clPlot.cpp : implementation file // #include "stdafx.h" #include "curvedrawing.h" #include "clPlot.h" #include "CurveDrawingView.h" #include "MyView.h" #include "malloc.h" #include <stdlib.h> #include <afxwin.h> #include <math.h> #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // clPlot clPlot::clPlot() { m_ctlBkColor= RGB(255,255,255); // m_ctlBkColor=RGB(255,0,0); m_gridColor = RGB(127,127,127); m_lNoValues=0; m_lend=0; leftmargin=30; rightmargin=30; topmargin=25; bottommargin=25; off=3; scalevalue=1; m_legendBkColor = RGB(255,255,255); } clPlot::~clPlot() { if(m_pValue!=NULL) free(m_pValue); } BEGIN_MESSAGE_MAP(clPlot, CWnd) //{{AFX_MSG_MAP(clPlot) // NOTE - the ClassWizard will add and remove mapping macros here. //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // clPlot message handlers void clPlot::DrawBasic(CDC* pDC) { CBrush brushctlBkColor(m_ctlBkColor); pDC->FillRect(m_ctlRect,&brushctlBkColor);//给CMyView视图填充背景色 //计算趋势图边框 m_plotRect.left=m_ctlRect.left+leftmargin; m_plotRect.right=m_ctlRect.right-rightmargin; m_plotRect.top=m_ctlRect.top+topmargin; m_plotRect.bottom=m_ctlRect.bottom-bottommargin; //绘制趋势图边框 pDC->Rectangle(m_plotRect); } void clPlot::DrawXAxisGrid(CDC *pDC) { CPen *old1, *old, pen(PS_SOLID, 1, m_gridColor);//大格笔 CPen stick(PS_SOLID,0,RGB(0,0,0));//刻度笔 CPen mline(PS_SOLID,0,RGB(192,192,192));//小格笔 //横向小格宽度,分为了100个小格,10个大格 smallgridwidth=((double)m_plotRect.right-(double)m_plotRect.left)/100; old1=pDC->SelectObject(&mline); double x; for(int i=1;i<=99;i++) { x=m_plotRect.left+smallgridwidth*i; //逢10画大格 if(0==i%10) { old=pDC->SelectObject(&pen); pDC->MoveTo(CPoint(x,m_plotRect.bottom-2)); pDC->LineTo(CPoint(x,m_plotRect.top+1)); pDC->SelectObject(old); } //非10画小格 else { pDC->MoveTo(CPoint(x,m_plotRect.bottom-2)); pDC->LineTo(CPoint(x,m_plotRect.top+1)); } //画横向刻度 old=pDC->SelectObject(&stick); pDC->MoveTo(CPoint(x,m_plotRect.top)); pDC->LineTo(CPoint(x,m_plotRect.top-off)); pDC->MoveTo(CPoint(x,m_plotRect.bottom)); pDC->LineTo(CPoint(x,m_plotRect.bottom+off)); pDC->SelectObject(old); } pDC->SelectObject(old1); } void clPlot::DrawYAxisGrid(CDC *pDC) { CPen *old, *old1, pen(PS_SOLID, 1, m_gridColor); CPen stick(PS_SOLID,0,RGB(0,0,0)); CPen mline(PS_SOLID,0,RGB(192,192,192)); CFont m_font; m_font.CreatePointFont(100,"Arial",pDC); pDC->SelectObject(&m_font); pDC->DrawText("1.0",CRect(m_plotRect.right+5,m_plotRect.bottom-10,m_plotRect.right+30,m_plotRect.bottom+10),DT_CENTER); pDC->DrawText("5.0",CRect(m_plotRect.right+5,m_plotRect.top-5,m_plotRect.right+30,m_plotRect.top+15),DT_CENTER); pDC->DrawText("1.0",CRect(m_plotRect.left-30,m_plotRect.bottom-10,m_plotRect.left-5,m_plotRect.bottom+10),DT_CENTER); pDC->DrawText("5.0",CRect(m_plotRect.left-30,m_plotRect.top-5,m_plotRect.left-5,m_plotRect.top+15),DT_CENTER); //竖向分为四十个小格,1-4V double smallgridwidth=((double)m_plotRect.top-(double)m_plotRect.bottom)/40; old1=pDC->SelectObject(&mline); double y; for(int i=1;i<=39;i++) { y=m_plotRect.bottom+smallgridwidth*i; if(0==i%10) { scalevalue++; old=pDC->SelectObject(&pen); pDC->MoveTo(CPoint(m_plotRect.right-2,y)); pDC->LineTo(CPoint(m_plotRect.left+1,y)); //输出竖向刻度值 char b[20]; sprintf(b,"%.1f",scalevalue); pDC->DrawText(b,CRect(m_plotRect.right+5,y-10,m_plotRect.right+30,y+10),DT_CENTER); pDC->DrawText(b,CRect(m_plotRect.left-30,y-10,m_plotRect.left-5,y+10),DT_CENTER); pDC->SelectObject(old); } else { pDC->MoveTo(CPoint(m_plotRect.right-2,y)); pDC->LineTo(CPoint(m_plotRect.left+1,y)); } //画竖向刻度 old=pDC->SelectObject(&stick); pDC->MoveTo(CPoint(m_plotRect.left,y)); pDC->LineTo(CPoint(m_plotRect.left-off,y)); pDC->MoveTo(CPoint(m_plotRect.right,y)); pDC->LineTo(CPoint(m_plotRect.right+off,y)); pDC->SelectObject(old); } pDC->SelectObject(old1); scalevalue=1; } BOOL clPlot::AddPoint(CTime valuetime, float value) { //为新产生的点分配内存,此处注意malloc与realloc if(m_lNoValues > 0) m_pValue = (pValue*)realloc(m_pValue, (m_lNoValues+1)*sizeof(pValue)); else m_pValue = (pValue*)malloc((m_lNoValues+1)*sizeof(pValue)); //注意m_pValue为指向pValue结构体的指针,但我们可以把当作数组来使用 m_pValue[m_lend].dValue=value; m_pValue[m_lend].ValueTime=valuetime; temp=value; m_lNoValues++; m_lend++; return TRUE; } void clPlot::DrawCurve(CDC* pDC,COLORREF pColor) { static int docnumber=0; docnumber++; CPen m_pen(PS_SOLID,1,pColor);//为趋势图曲线建立的红色画笔 CPen* m_oldpen=pDC->SelectObject(&m_pen); //实验用的产生1-4的随机数 float y=(double)(abs(rand())%20); float cy=y/4; if(cy<=1) { cy=1; } //以上为实验用数 //将随机产生的存入内存(实时数据库) if(cy==1) AddPoint(CTime::GetCurrentTime(),temp); else AddPoint(CTime::GetCurrentTime(),cy); //当有了两个数据后才可以画第一条线 if(docnumber>=2) { int docnumber1=docnumber; //计算我们的坐标和趋势图外框尺寸之间的比例 intervalY=m_plotRect.Height()/4; //点的个数小于等于101时 if(docnumber<=100) { for(int i=0;i<docnumber-1;i++) { docnumber1--; //注意VC的GDI视图的Y坐标正向是朝下的,所以我们需要m_plotRect.Height()+topmargin-视图中的位置 pDC->MoveTo(CPoint(m_plotRect.left+smallgridwidth*(100-docnumber1),m_plotRect.Height()+topmargin- ((m_pValue[i].dValue-1)*intervalY))); pDC->LineTo(CPoint(m_plotRect.left+smallgridwidth*(100-docnumber1+1),m_plotRect.Height()+topmargin- ((m_pValue[i+1].dValue-1)*intervalY))); } } //点的格数大于101时,由于我们的趋势图只能显示101个点(100个格),所以当点的个数超过 //101时,我们需要显示后101个点 else { for(int i=0;i<100;i++) { pDC->MoveTo(CPoint(m_plotRect.left+smallgridwidth*(i),m_plotRect.Height()+topmargin- ((m_pValue[i+docnumber-1-100].dValue-1)*intervalY))); pDC->LineTo(CPoint(m_plotRect.left+smallgridwidth*(i+1),m_plotRect.Height()+topmargin- ((m_pValue[i+docnumber-100].dValue-1)*intervalY))); } } pDC->SelectObject(m_oldpen); CFont font; font.CreatePointFont(100,"Arial",pDC); pDC->SelectObject(&font); int num=docnumber; for(int i=0;i<=10,num>=0;i++) { CString str=m_pValue[num-1].ValueTime.Format("%H:%M:%S"); pDC->DrawText(str,CRect(m_plotRect.right-smallgridwidth*i*10-30,m_plotRect.bottom+5, m_plotRect.right-smallgridwidth*i*10+30,m_plotRect.bottom+25),DT_CENTER); num-=10; } } } void clPlot::DrawLegend(CDC *pDC) { //m_legendRect为左上小图标的区域 m_legendRect.top=m_plotRect.top+50; m_legendRect.bottom=m_plotRect.top-15; m_legendRect.left=m_plotRect.left+20; m_legendRect.right=m_plotRect.left+150; CPen pen(PS_SOLID, 1, RGB(0,0,0)); CPen *oPen = pDC->SelectObject(&pen); CBrush *oBrush , brush(m_legendBkColor); oBrush = pDC->SelectObject(&brush); pDC->Rectangle(m_legendRect); pDC->SelectObject(oBrush); CPen m_pen(PS_SOLID,1,RGB(255,0,0));//为趋势图曲线建立的红色画笔 pDC->SelectObject(&m_pen); pDC->MoveTo(CPoint(m_legendRect.left+10,m_legendRect.bottom+10)); pDC->LineTo(CPoint(m_legendRect.left+40,m_legendRect.bottom+10)); CFont m_font; m_font.CreatePointFont(90,"Arial",pDC); pDC->SelectObject(&m_font); pDC->TextOut(m_legendRect.left+60,m_legendRect.bottom+5,"通道0"); pDC->SelectObject(oPen); } void clPlot::DrawLegendShadow(CDC *pDC) { CPen pen(PS_SOLID, 1, RGB(127,127,127)); CPen *oPen = pDC->SelectObject(&pen); CBrush *oBrush , brush(RGB(127,127,127)); oBrush = pDC->SelectObject(&brush); pDC->Rectangle(CRect(m_legendRect.left+5,m_legendRect.top+5,m_legendRect.right+5, m_legendRect.bottom+5)); pDC->SelectObject(oBrush); pDC->SelectObject(oPen); }